package com.atguigu.gulimall.search.thread;

import java.util.concurrent.*;

public class ThreadNewTest {

    // 创建一个线程池
    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start");
        // CompletableFuture启动异步任务  无返回值
        /*CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
            System.out.println("Thread01当前线程号 -> " + Thread.currentThread().getId());
            int n = 10 / 5;
            System.out.println(n);
        }, executor);*/
        /**
         * CompletableFuture启动异步任务  有返回值
         * 方法执行完后的感知
         */
        /*CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.out.println("Thread01当前线程号 -> " + Thread.currentThread().getId());
            int n = 10 / 0;
            System.out.println(n);
            return n;
        }, executor).whenComplete((res,exeption) -> {// 虽然可以得到异常信息，但是无法处理异常返回数据
            System.out.println("异步任务成功完成，结果是：" + res + "异常是：" + exeption);
        }).exceptionally(throwable -> {// 可以感知异常，同时返回默认值
            System.out.println("throwable = " + throwable);
            return 2;
        });*/
        /**
         * 方法执行完成后处理返回结果或异常
         */
        /*CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            System.out.println("Thread01当前线程号 -> " + Thread.currentThread().getId());
            int n = 10 / 2;
            System.out.println(n);
            return n;
        }, executor).handle((res,exeption) -> {
            if (res != null){
                return res * 2;
            }
            if (exeption != null){
                return 2;
            }
            return 0;
        });
        Object integer = supplyAsync.get();
        System.out.println("integer = " + integer);*/
        /**
         * 线程串行化
         * 1）、thenRun: 不能获取上一步的执行结果，无返回值
         *      .thenRunAsync( () -> {
         *             System.out.println("任务2启动了");
         *         },executor);
         * 2）、thenAcceptAsync 能接受上一步的结果，但是无返回值
         *      thenAcceptAsync(res -> {
         *             System.out.println("res = " + res);
         *         },executor);
         * 3)、thenApplyAsync 能接受上一步的结果， 也有返回值
         */
        /*CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("Thread01当前线程号 -> " + Thread.currentThread().getId());
            int n = 10 / 2;
            System.out.println(n);
            return n;
        }, executor).thenApplyAsync(res -> {

            System.out.println("线程二启动了。。。。。");
            return "成功调用第一步结果";
        }, executor);
        String result = future.get();// get是阻塞方法 */

        /**
         * 两任务组合
         * 1）、thenCombine: 组合两个future，获取两个future的返回结果，并返回当前任务的返回值
         * 2）、thenAcceptBoth：组合两个future,获取两个future任务的返回结果，然后处理任务，没有返回结果
         * 3）、runAfterBoth: 组合两个future,不需要获取future的结果，只需要两个future处理完成后，处理该任务
         */
        /*CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程开始 -> " + Thread.currentThread().getId());
            int n = 10 / 2;
            System.out.println("任务1线程结束 -> " + n);
            return n;
        }, executor);

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程开始 -> " + Thread.currentThread().getId());
            System.out.println("任务2线程结束 -> ");
            return "Hello 任务二";
        }, executor);

        future1.runAfterBothAsync(future2,() -> {
            System.out.println("任务3开始执行。。。");
        },executor);

        CompletableFuture<String> future = future1.thenCombineAsync(future2, (res1, res2) -> {
            System.out.println("任务3执行，返回结果");
            return res1 + res2;
        }, executor);
        System.out.println("future = " + future.get());

        future1.thenAcceptBothAsync(future2,(res1, res2) -> {
            System.out.println("任务3执行，不返回结果" + res1 + res2);
        },executor);*/
        /**
         * 两任务组合 任一个完成  执行第三个任务
         *
         * 1）、applyToEither: 两任务有一个任务执行完成。获取它的返回值，处理任务，并有新的返回值
         * 2）、acceptEither: 两任务有一个任务执行完成。获取它的返回值，处理任务，没有新的返回值
         * 3）、runAfterEither: 两任务有一个任务执行完成。不需要获取它的返回结果，处理任务，也没有返回值
         */
        /*CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1线程开始 -> " + Thread.currentThread().getId());
            int n = 10 / 2;
            System.out.println("任务1线程结束 -> " + n);
            return n;
        }, executor);

        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2线程开始 -> " + Thread.currentThread().getId());
            try {
                Thread.sleep(3000);
                System.out.println("任务2线程结束 -> ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello 任务二";
        }, executor);

        future1.runAfterEitherAsync(future2,() -> {
            System.out.println("我是任务3");
        },executor);

        future1.acceptEitherAsync(future2,res -> {
            System.out.println("res = " + res);
        },executor);

        CompletableFuture<String> future = future1.applyToEitherAsync(future2, res -> {
            System.out.println("res = " + res);
            return "我是任务3的返回结果";
        }, executor);
        System.out.println("future.get() = " + future.get());*/

        /**
         * 多任务组合
         *
         * allOf: 等待所有任务完成
         * anyOf: 只要有一个任务完成
         */

        CompletableFuture<String> task01 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("任务1--------");
                return "任务1完成";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "任务1异常";
            }
        }, executor);

        CompletableFuture<String> task02 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("任务2--------");
                return "任务2完成";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "任务2异常";
            }
        }, executor);

        CompletableFuture<String> task03 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
                System.out.println("任务3--------");
                return "任务3完成";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "任务3异常";
            }
        }, executor);

        /*CompletableFuture<Void> future = CompletableFuture.allOf(task01, task02, task03);
        future.get();// 阻塞等待查看效果*/

        CompletableFuture<Object> future = CompletableFuture.anyOf(task01, task02, task03);
        future.get();// 阻塞等待查看效果
        System.out.println("main...end");
    }

    public static void testThread(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start");

        /*Thread01 thread01 = new Thread01();
        thread01.start();*/

        /*Runnable01 runnable01 = new Runnable01();
        new Thread(runnable01).start();*/


        //  FutureTask -> RunnableFuture -> Runnable

        /*FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable01());
        new Thread(futureTask).start();
        // 若要等待异步返回结果 则阻塞执行  否则异步执行
        Integer integer = futureTask.get();
        System.out.println("integer = " + integer);*/

        /**
         * 1、2 两种方式无返回值 无法处理异常  无法控制资源消耗
         * 3、有返回值、可以处理异常  也无法控制资源消耗
         * 4、可以有也可以没有返回值 看调用的方法 可以控制池大小 控制资源消耗
         */
//        executor.submit(new Runnable01());

        /**
         *
         *  原生线程池的七大参数
         *
         * 1、corePoolSize 线程池常驻核心线程数
         * 创建线程池后，当有请求任务来之后，就会安排池中线程去执行请求任务，近似理解为今日当值线程。
         * 当线程池中的线程数目达到了corePoolSize后，就会把任务放到缓存队列中；
         * 2、maxmumPoolSize:
         * 线程池能够容纳同时执行的最大线程数，此值必须大于等于1
         * 3、keepAliveTime：多余空闲线程的存活时间。
         * 当前线程池的数量超过corePoolSize时，当空闲时间达到keepAliveTime值时，多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。
         * 4、unit:keepAliveTime的时间单位
         * 5、workQueue：任务队列，被提交但未被执行的任务
         * 6、threadFactory：表示生成线程池中线程的线程工厂，用于创建线程，一般用默认的即可
         * 7、handler：拒绝策略，表示当队列满了并且工作线程大于等于线程池的最大线程数（maxmumPoolSize）
         *
         * 作者：香山上的麻雀
         * 链接：https://www.jianshu.com/p/c59735134bae
         *
         * 面试题：一个线程池，core 7 ,max 20 ,queue 50 100并发进来怎么分配的；
         * 7个会立即得到执行(开启start方法)，50个会进入阻塞队列，再开13个进行执行。剩下的30个就使用拒绝策略
         * 如果不想抛弃还要执行。那么执行CallerRunsPolicy策略 直接调用异步执行的方法
         *
         *
         * Java通过Executors提供四种线程池，分别为：
         * 1、newCachedThreadPool创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。
         *    core是0，所有都可回收
         * 2、newFixedThreadPool 创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。
         *    固定大小，core=max,都不可回收
         * 3、newScheduledThreadPool 创建一个定长线程池，支持定时及周期性任务执行。
         *   定时任务的线程池  可以指定延迟执行的时间
         * 4、newSingleThreadExecutor 创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
         *   单线程的线程池，后台从队列里面获取任务，挨个执行
         * 链接：
         */
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,
                20,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        System.out.println("main...end");


    }

    public static class Callable01 implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("Thread01当前线程号 -> " + Thread.currentThread().getId());
            int n = 10 /5;
            System.out.println(n);
            return n;
        }
    }

    public static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.println("Thread01当前线程号 -> " + Thread.currentThread().getId());
            int n = 10 /5;
            System.out.println(n);
        }
    }

    public static class Thread01 extends Thread{
        @Override
        public void run() {
            System.out.println("Thread01当前线程号 -> " + Thread.currentThread().getId());
            int n = 10 /5;
            System.out.println(n);
        }
    }
}
